package biopepa;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

public class NewSpecies {
	public String speciesName;
	public int speciesUpper;
	public int speciesLower;
	public int speciesInitial;
	public boolean isContinuous;
	public boolean hasComponent;
	private HashMap< String , ActionEnabled > actionsEnabledObjects;
	public HashMap< NewSpecies , ArrayList<ActionEnabled> > speciesCoop;
	public HashMap< NewCompositionalDef , ArrayList<ActionEnabled> > compositionalDefCoop;
	public HashMap<String , LocationAndInitial> locationsAccessible;
	
	public NewSpecies(String name){
		
		this.speciesName = name;
		this.speciesLower = 0;
		speciesInitial = -1;
		//this.speciesType = Type.discrete;
		isContinuous = false;
		actionsEnabledObjects = new HashMap< String , ActionEnabled > ();
		this.compositionalDefCoop = new HashMap< NewCompositionalDef , ArrayList<ActionEnabled> >();
		this.speciesCoop = new HashMap< NewSpecies , ArrayList<ActionEnabled> > () ;
		this.locationsAccessible = new HashMap<String , LocationAndInitial>();
		
	}
	
	public ActionEnabled getActionEnabled(String name){
		ActionEnabled action = actionsEnabledObjects.get(name);
		return action;
	}
	
	public HashMap< String , ActionEnabled > getActionsEnabledObjects(){
		HashMap< String , ActionEnabled > list = actionsEnabledObjects;
		return list;
	}

	
	public void setUpper(SpeciesAndLocations speciesAndLocations , String upper){
		
		if(speciesAndLocations.hasLocations == true){
		int i;
		int size =speciesAndLocations.locations.size();
		for(i=0; i<size; i++){
			speciesAndLocations.locations.get(i).upper = Integer.parseInt(upper);
			String name = speciesAndLocations.locations.get(i).location.locationName;
			locationsAccessible.put(name, speciesAndLocations.locations.get(i));			
		}
		}
		else{
			speciesUpper = Integer.parseInt(upper);
		}
	}

	public void setSpeciesLower(SpeciesAndLocations speciesAndLocations , String lower){
		if(speciesAndLocations.hasLocations == true){
			int i;
			int size =speciesAndLocations.locations.size();
			for(i=0; i<size; i++){
				speciesAndLocations.locations.get(i).lower = Integer.parseInt(lower);
				String name = speciesAndLocations.locations.get(i).location.locationName;
				locationsAccessible.put(name, speciesAndLocations.locations.get(i));			
			}
			}
			else{
				speciesLower = Integer.parseInt(lower);
			}
	}
	
	public void setSpeciesInitial(String num){
		speciesInitial = Integer.parseInt(num);
	}
	
	public void setSpeciesType(String newType){
		if(newType == "continuous"){
		isContinuous = true;
		}
	}
	
	public boolean isLocation(String name){
		boolean bool;
		bool = false;
		if(locationsAccessible.containsKey(name)){
			bool=true;
		}
		return bool;
	}
	
	public void addActionEnabled(String name, String stoich, String op){
		ActionEnabled action;
		action = new ActionEnabled(name , stoich , op);
		action.isContinuous = this.isContinuous;
	    actionsEnabledObjects.put(name , action);
	}
	
	public void addActionEnabled(ActionEnabled action){
		if(this.actionsEnabledObjects.containsKey(action.actionEnabledName) == true){
			ActionEnabled action2 = this.actionsEnabledObjects.get(action.actionEnabledName);
			Iterator iterator = action.locations.keySet().iterator();
			while(iterator.hasNext()){
				String key = iterator.next().toString();
				NewLocation loc = action.locations.get(key);
				action2.locations.put(loc.locationName, loc);
				//System.out.println("ora con loc " + action2.locations);
			}
		}
		else{
			actionsEnabledObjects.put(action.actionEnabledName , action);
			//System.out.println("aggiunta action enabled " +  action.actionEnabledName + " in " + action.locations + " per " + this.speciesName);
		}
	    //actionsEnabledObjects.put(action.actionEnabledName , action);
	}
	
	public void addActionsEnabledCoop(NewSpecies species , ArrayList<ActionEnabled> actionList){
	    speciesCoop.put(species , actionList);
	}
	
	public void addLocationsAccessible(LocationAndInitial locationAndInitial){
	    locationsAccessible.put(locationAndInitial.location.locationName , locationAndInitial);
	}
	
	public void addLocationsAccessible(NewLocation newLocation){
		LocationAndInitial newLocationAndInitial = new LocationAndInitial(newLocation);
	    locationsAccessible.put(newLocationAndInitial.location.locationName , newLocationAndInitial);
	}
	
	public void addLocationsAccessibleArray(ArrayList<LocationAndInitial> locations){
		int size = locations.size();
		int i;
		for(i=0; i<size; i++){
			addLocationsAccessible(locations.get(i));
		}
	}
	
	public void addInitialValues(ArrayList<LocationAndInitial> newLocations , String value){
		int newLocationsSize = newLocations.size();
		int i;
			for(i=0; i<newLocationsSize; i++)
			{ 
				String loc = newLocations.get(i).location.locationName;
				if(locationsAccessible.get(loc).initial != 0){
					throw new BiopepaException("Error: multiple definition for initial value for the species '" + this.speciesName + "' in location '" + loc + "'.");
				}
				else{
					locationsAccessible.get(loc).initial = Integer.parseInt(value);	
				}
			}
	}
	
	public void addInitialValues2(ArrayList<LocationAndInitial> newLocations , String value){
		int newLocationsSize = newLocations.size();
		int i;
			for(i=0; i<newLocationsSize; i++)
			{ 
				String loc = newLocations.get(i).location.locationName;
				if(locationsAccessible.get(loc).initial != 0){
					throw new BiopepaException("Error: multiple definition for initial value for the species '" + this.speciesName + "' in location '" + loc + "'.");
				}
				else{
					locationsAccessible.get(loc).initial = Integer.parseInt(value);	
				}
			}
	}
	
	public String getSpeciesName(NewSpecies newName) {
		return newName.speciesName;
	}
	
	public boolean isActionEnabled(String name) {
        return actionsEnabledObjects.containsKey(name);
    }
	
		//Controllo1: Aggiunge l'azione nel caso in cui non sia presente
	
			public void actionsEnabledCheck1(String name){
				if(isActionEnabled(name) == true)
				{ }
				else
				{ addActionEnabled(name , null , null);
				}
			}
		
		//Controllo: aggiunge locations nel caso in cui non ci siano
		public void locationCheck(ArrayList<LocationAndInitial> locationAndInitial){
			int i;
	        int size = locationAndInitial.size();
	        for(i=0; i<size; i++){
	           if(isLocation(locationAndInitial.get(i).location.locationName) == false){
	             addLocationsAccessible(locationAndInitial.get(i));
	           }
	        }
		}
		

		public void actionEnabledCheck2(SpeciesAndAction speciesAndAction){
			
//				 if(speciesAndAction.isDisplacement == false){
					 int i;
					 int locSize = speciesAndAction.locations.size();
					 if(locSize == 0){
						 ActionEnabled actionToAdd; 
						 actionToAdd = new ActionEnabled( speciesAndAction.actionName , speciesAndAction.stoich , speciesAndAction.operator );
						 actionToAdd.isContinuous = this.isContinuous;
						 addActionEnabled(actionToAdd);
					 	}
					 else{	 
						 for(i=0; i<locSize; i++){
							 ActionEnabled actionToAdd; 
							 actionToAdd = new ActionEnabled( speciesAndAction.actionName, speciesAndAction.locations.get(i) , speciesAndAction.stoich , speciesAndAction.operator );		
							 actionToAdd.isContinuous = this.isContinuous;
							 actionToAdd.isDisplacement = speciesAndAction.isDisplacement;
							 actionToAdd.location1 = speciesAndAction.location1;
							 actionToAdd.location2 = speciesAndAction.location2;
							 addActionEnabled(actionToAdd);
							 if(isLocation(speciesAndAction.locations.get(i).location.locationName) == false){
								 addLocationsAccessibleArray(speciesAndAction.locations);
							 }
						 	}
					 	}
//				 }
//				 else{
//					 addDisplacement(speciesAndAction.actionName, speciesAndAction.stoich, speciesAndAction.operator , speciesAndAction.locations.get(0), speciesAndAction.locations.get(1) );
//					 int size  = speciesAndAction.locations.size();
//		             int i;
//		             for(i=0; i<size; i++){
//		            	 NewLocation loc = speciesAndAction.locations.get(i).location;
//		            	 if(this.locationsAccessible.containsKey(loc.locationName) == false){
//		            		 this.locationsAccessible.put(loc.locationName, speciesAndAction.locations.get(i));
//		            	 }
//		             }
//				 }
		}
		
		//Controllo3: Controlla che tutte le azioni presenti nella comp modello siano definite
		
		public void actionEnabledCheck3(String name){
		      if(isActionEnabled(name) == true)
			  { }
			 else{ 
				 throw new BiopepaException("Action '" + name + "' in model component is undefined.");
			   }
		}
		
		//Controllo1: Controlla che nella model component le location siano accessibili per la species
		public void checkLocationAccessible(ArrayList<LocationAndInitial> locations){
			int locationsSize=locations.size();
			int i;
			for(i=0; i<locationsSize; i++){
				String loc = locations.get(i).location.locationName;
				if( locationsAccessible.containsKey(loc)){					
				}
				else{
					throw new BiopepaException("Error: location '" + loc + "' is not accessible for the species '" + this.speciesName + "'.");
				}
			}
		}




}
